home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 30
/
Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso
/
Aminet
/
gfx
/
misc
/
gnuplot-3.7src.lha
/
gnuplot-3.7src
/
gnuplot-3.7.lha
/
gnuplot-3.7
/
parse.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-11-19
|
14KB
|
649 lines
#ifndef lint
static char *RCSid = "$Id: parse.c,v 1.62 1998/06/18 14:55:13 ddenholm Exp $";
#endif
/* GNUPLOT - parse.c */
/*[
* Copyright 1986 - 1993, 1998 Thomas Williams, Colin Kelley
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted, but not the right to
* distribute the complete modified source code. Modifications are to
* be distributed as patches to the released version. Permission to
* distribute binaries produced by compiling modified sources is granted,
* provided you
* 1. distribute the corresponding source modifications from the
* released version in the form of a patch file along with the binaries,
* 2. add special version identification to distinguish your version
* in addition to the base release version number,
* 3. provide your name and address as the primary contact for the
* support of your modified version, and
* 4. retain our contact information in regard to use of the base
* software.
* Permission to distribute the released version of the source code along
* with corresponding source modifications in the form of a patch file is
* granted with same provisions 2 through 4 for binary distributions.
*
* This software is provided "as is" without express or implied warranty
* to the extent permitted by applicable law.
]*/
#include <signal.h>
#include "plot.h"
#include "help.h"
#include <setjmp.h>
RETSIGTYPE fpe __PROTO((int an_int));
static void extend_at __PROTO((void));
static union argument *add_action __PROTO((enum operators sf_index));
static void express __PROTO((void));
static void xterm __PROTO((void));
static void aterm __PROTO((void));
static void bterm __PROTO((void));
static void cterm __PROTO((void));
static void dterm __PROTO((void));
static void eterm __PROTO((void));
static void fterm __PROTO((void));
static void gterm __PROTO((void));
static void hterm __PROTO((void));
static void factor __PROTO((void));
static void xterms __PROTO((void));
static void aterms __PROTO((void));
static void bterms __PROTO((void));
static void cterms __PROTO((void));
static void dterms __PROTO((void));
static void eterms __PROTO((void));
static void fterms __PROTO((void));
static void gterms __PROTO((void));
static void hterms __PROTO((void));
static void iterms __PROTO((void));
static void unary __PROTO((void));
static struct at_type *at = NULL;
static int at_size = 0;
#if defined(_Windows) && !defined(WIN32)
static jmp_buf far fpe_env;
#else
static jmp_buf fpe_env;
#endif
#define dummy (struct value *) 0
RETSIGTYPE fpe(an_int)
int an_int;
{
#if defined(MSDOS) && !defined(__EMX__) && !defined(DJGPP) && !defined(_Windows) || defined(DOS386)
/* thanks to lotto@wjh12.UUCP for telling us about this */
_fpreset();
#endif
#ifdef OS2
(void) signal(an_int, SIG_ACK);
#else
(void) signal(SIGFPE, (sigfunc) fpe);
#endif
undefined = TRUE;
longjmp(fpe_env, TRUE);
}
#ifdef apollo
#include <apollo/base.h>
#include <apollo/pfm.h>
#include <apollo/fault.h>
/*
* On an Apollo, the OS can signal a couple errors that are not mapped into
* SIGFPE, namely signalling NaN and branch on an unordered comparison. I
* suppose there are others, but none of these are documented, so I handle
* them as they arise.
*
* Anyway, we need to catch these faults and signal SIGFPE.
*/
pfm_$fh_func_val_t apollo_sigfpe(pfm_$fault_rec_t & fault_rec)
{
kill(getpid(), SIGFPE);
return pfm_$continue_fault_handling;
}
apollo_pfm_catch()
{
status_$t status;
pfm_$establish_fault_handler(fault_$fp_bsun, pfm_$fh_backstop,
apollo_sigfpe, &status);
pfm_$establish_fault_handler(fault_$fp_sig_nan, pfm_$fh_backstop,
apollo_sigfpe, &status);
}
#endif
void evaluate_at(at_ptr, val_ptr)
struct at_type *at_ptr;
struct value *val_ptr;
{
double temp;
undefined = FALSE;
errno = 0;
reset_stack();
#ifndef DOSX286
if (setjmp(fpe_env))
return; /* just bail out */
(void) signal(SIGFPE, (sigfunc) fpe);
#endif
execute_at(at_ptr);
#ifndef DOSX286
(void) signal(SIGFPE, SIG_DFL);
#endif
if (errno == EDOM || errno == ERANGE) {
undefined = TRUE;
} else if (!undefined) { /* undefined (but not errno) may have been set by matherr */
(void) pop(val_ptr);
check_stack();
/* At least one machine (ATT 3b1) computes Inf without a SIGFPE */
temp = real(val_ptr);
if (temp > VERYLARGE || temp < -VERYLARGE) {
undefined = TRUE;
}
}
#if defined(NeXT) || defined(ultrix)
/*
* linux was able to fit curves which NeXT gave up on -- traced it to
* silently returning NaN for the undefined cases and plowing ahead
* I can force that behavior this way. (0.0/0.0 generates NaN)
*/
if (undefined && (errno == EDOM || errno == ERANGE)) { /* corey@cac */
undefined = FALSE;
errno = 0;
Gcomplex(val_ptr, 0.0 / 0.0, 0.0 / 0.0);
}
#endif /* NeXT || ultrix */
}
struct value *
const_express(valptr)
struct value *valptr;
{
register int tkn = c_token;
if (END_OF_COMMAND)
int_error("constant expression required", c_token);
/* div - no dummy variables in a constant expression */
dummy_func = NULL;
evaluate_at(temp_at(), valptr); /* run it and send answer back */
if (undefined) {
int_error("undefined value", tkn);
}
return (valptr);
}
/* if dummy_dunc == NULL on entry, do not attempt to compile dummy variables
* - div
*/
struct at_type *
temp_at()
{
/* build a static action table and return its
* pointer */
if (at != NULL) {
free(at);
at = NULL;
}
at = (struct at_type *) gp_alloc(sizeof(struct at_type), "action table");
at->a_count = 0; /* reset action table !!! */
at_size = MAX_AT_LEN;
express();
return (at);
}
/* build an action table, put it in dynamic memory, and return its pointer */
struct at_type *
perm_at()
{
register struct at_type *at_ptr;
unsigned int len;
(void) temp_at();
len = sizeof(struct at_type) +
(int) (at->a_count - MAX_AT_LEN) * (int) sizeof(struct at_entry);
at_ptr = (struct at_type *) gp_realloc(at, (unsigned long) len, "perm_at");
at = NULL; /* invalidate at pointer */
return (at_ptr);
}
static void extend_at()
{
int newsize = sizeof(struct at_type) + at_size * sizeof(struct at_entry);
at = gp_realloc(at, newsize, "extend_at");
at_size += MAX_AT_LEN;
FPRINTF((stderr, "Extending at size to %d\n", at_size));
}
/* moved from eval.c, the function is only called from this module */
static union argument *
add_action(sf_index)
enum operators sf_index; /* index of p-code function */
{
if (at->a_count >= at_size) {
extend_at();
}
at->actions[at->a_count].index = sf_index;
return (&(at->actions[at->a_count++].arg));
}
static void express()
{ /* full expressions */
xterm();
xterms();
}
static void xterm()
{ /* ? : expressions */
aterm();
aterms();
}
static void aterm()
{
bterm();
bterms();
}
static void bterm()
{
cterm();
cterms();
}
static void cterm()
{
dterm();
dterms();
}
static void dterm()
{
eterm();
eterms();
}
static void eterm()
{
fterm();
fterms();
}
static void fterm()
{
gterm();
gterms();
}
static void gterm()
{
hterm();
hterms();
}
static void hterm()
{
unary(); /* - things */
iterms(); /* * / % */
}
static void factor()
{
if (equals(c_token, "(")) {
c_token++;
express();
if (!equals(c_token, ")"))
int_error("')' expected", c_token);
c_token++;
} else if (equals(c_token, "$")) {
struct value a;
if (!isanumber(++c_token))
int_error("Column number expected", c_token);
convert(&a, c_token++);
if (a.type != INTGR || a.v.int_val < 0)
int_error("Positive integer expected", c_token);
add_action(DOLLARS)->v_arg = a;
} else if (isanumber(c_token)) {
/* work around HP 9000S/300 HP-UX 9.10 cc limitation ... */
#if defined(__hpux) && defined(__hp9000s300) && !defined(__GNUC__)
union argument *foo = add_action(PUSHC);
convert(&(foo->v_arg), c_token);
#else
convert(&(add_action(PUSHC)->v_arg), c_token);
#endif
c_token++;
} else if (isletter(c_token)) {
if ((c_token + 1 < num_tokens) && equals(c_token + 1, "(")) {
enum operators value = standard(c_token);
if (value) { /* it's a standard function */
c_token += 2;
express();
if (equals(c_token, ",")) {
while (equals(c_token, ",")) {
c_token += 1;
express();
}
}
if (!equals(c_token, ")"))
int_error("')' expected", c_token);
c_token++;
(void) add_action(value);
} else {
enum operators call_type = (int) CALL;
int tok = c_token;
c_token += 2;
express();
if (equals(c_token, ",")) {
struct value num_params;
num_params.type = INTGR;
num_params.v.int_val = 1;
while (equals(c_token, ",")) {
num_params.v.int_val += 1;
c_token += 1;
express();
}
add_action(PUSHC)->v_arg = num_params;
call_type = (int) CALLN;
}
if (!equals(c_token, ")"))
int_error("')' expected", c_token);
c_token++;
add_action(call_type)->udf_arg = add_udf(tok);
}
/* dummy_func==NULL is a flag to say no dummy variables active */
} else if (dummy_func) {
if (equals(c_token, c_dummy_var[0])) {
c_token++;
add_action(PUSHD1)->udf_arg = dummy_func;
} else if (equals(c_token, c_dummy_var[1])) {
c_token++;
add_action(PUSHD2)->udf_arg = dummy_func;
} else {
int i, param = 0;
for (i = 2; i < MAX_NUM_VAR; i++) {
if (equals(c_token, c_dummy_var[i])) {
struct value num_params;
num_params.type = INTGR;
num_params.v.int_val = i;
param = 1;
c_token++;
add_action(PUSHC)->v_arg = num_params;
add_action(PUSHD)->udf_arg = dummy_func;
break;
}
}
if (!param) { /* defined variable */
add_action(PUSH)->udv_arg = add_udv(c_token);
c_token++;
}
}
/* its a variable, with no dummies active - div */
} else {
add_action(PUSH)->udv_arg = add_udv(c_token);
c_token++;
}
}
/* end if letter */
else
int_error("invalid expression ", c_token);
/* add action code for ! (factorial) operator */
while (equals(c_token, "!")) {
c_token++;
(void) add_action(FACTORIAL);
}
/* add action code for ** operator */
if (equals(c_token, "**")) {
c_token++;
unary();
(void) add_action(POWER);
}
}
static void xterms()
{
/* create action code for ? : expressions */
if (equals(c_token, "?")) {
register int savepc1, savepc2;
register union argument *argptr1, *argptr2;
c_token++;
savepc1 = at->a_count;
argptr1 = add_action(JTERN);
express();
if (!equals(c_token, ":"))
int_error("expecting ':'", c_token);
c_token++;
savepc2 = at->a_count;
argptr2 = add_action(JUMP);
argptr1->j_arg = at->a_count - savepc1;
express();
argptr2->j_arg = at->a_count - savepc2;
}
}
static void aterms()
{
/* create action codes for || operator */
while (equals(c_token, "||")) {
register int savepc;
register union argument *argptr;
c_token++;
savepc = at->a_count;
argptr = add_action(JUMPNZ); /* short-circuit if already
* TRUE */
aterm();
argptr->j_arg = at->a_count - savepc; /* offset for jump */
(void) add_action(BOOLE);
}
}
static void bterms()
{
/* create action code for && operator */
while (equals(c_token, "&&")) {
register int savepc;
register union argument *argptr;
c_token++;
savepc = at->a_count;
argptr = add_action(JUMPZ); /* short-circuit if already
* FALSE */
bterm();
argptr->j_arg = at->a_count - savepc; /* offset for jump */
(void) add_action(BOOLE);
}
}
static void cterms()
{
/* create action code for | operator */
while (equals(c_token, "|")) {
c_token++;
cterm();
(void) add_action(BOR);
}
}
static void dterms()
{
/* create action code for ^ operator */
while (equals(c_token, "^")) {
c_token++;
dterm();
(void) add_action(XOR);
}
}
static void eterms()
{
/* create action code for & operator */
while (equals(c_token, "&")) {
c_token++;
eterm();
(void) add_action(BAND);
}
}
static void fterms()
{
/* create action codes for == and !=
* operators */
while (TRUE) {
if (equals(c_token, "==")) {
c_token++;
fterm();
(void) add_action(EQ);
} else if (equals(c_token, "!=")) {
c_token++;
fterm();
(void) add_action(NE);
} else
break;
}
}
static void gterms()
{
/* create action code for < > >= or <=
* operators */
while (TRUE) {
/* I hate "else if" statements */
if (equals(c_token, ">")) {
c_token++;
gterm();
(void) add_action(GT);
} else if (equals(c_token, "<")) {
c_token++;
gterm();
(void) add_action(LT);
} else if (equals(c_token, ">=")) {
c_token++;
gterm();
(void) add_action(GE);
} else if (equals(c_token, "<=")) {
c_token++;
gterm();
(void) add_action(LE);
} else
break;
}
}
static void hterms()
{
/* create action codes for + and - operators */
while (TRUE) {
if (equals(c_token, "+")) {
c_token++;
hterm();
(void) add_action(PLUS);
} else if (equals(c_token, "-")) {
c_token++;
hterm();
(void) add_action(MINUS);
} else
break;
}
}
static void iterms()
{
/* add action code for * / and % operators */
while (TRUE) {
if (equals(c_token, "*")) {
c_token++;
unary();
(void) add_action(MULT);
} else if (equals(c_token, "/")) {
c_token++;
unary();
(void) add_action(DIV);
} else if (equals(c_token, "%")) {
c_token++;
unary();
(void) add_action(MOD);
} else
break;
}
}
static void unary()
{
/* add code for unary operators */
if (equals(c_token, "!")) {
c_token++;
unary();
(void) add_action(LNOT);
} else if (equals(c_token, "~")) {
c_token++;
unary();
(void) add_action(BNOT);
} else if (equals(c_token, "-")) {
c_token++;
unary();
(void) add_action(UMINUS);
} else if (equals(c_token, "+")) { /* unary + is no-op */
c_token++;
unary();
} else
factor();
}